home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 22
/
Cream of the Crop 22.iso
/
program
/
euphor14.zip
/
SEARCH.EX
< prev
next >
Wrap
Text File
|
1996-05-31
|
11KB
|
445 lines
-- This program searches for a string in files of the current directory
-- and subdirectories.
-- usage:
-- search [string]
--
-- If you don't supply a string on the command line you will be prompted
-- for it. The string may contain * and ? wildcard characters and so may
-- the list of file specifications. Lines containing the string are
-- displayed on the screen, and also recorded in C:\SEARCH.OUT.
-- Some statistics are printed at the end.
-- Example:
--
-- C:\> search
-- string: p?oc*re
-- match case? (n)
-- file-spec (*.*): *.e *.ex
-- scan subdirectories? (y)
--
-- Note: if you just hit Enter instead of supplying a string to search for,
-- the program will simply print any file names that match your file-spec.
-------- some user-modifiable parameters:
sequence log_name, log_path
log_name = "search.out"
log_path = "c:\\" & log_name -- place to store results
-- when you search "*.*" the following files
-- will actually be skipped (to save time):
sequence skip_list
skip_list = {
"*.EXE", "*.ZIP", "*.BMP", "*.GIF", "*.OBJ",
"*.DLL", "*.OBJ", "*.SWP", "*.PAR", "*.JPG"
}
-------- end of user-modifiable parameters
without type_check
include file.e
include wildcard.e
include sort.e
include graphics.e
constant KEYB = 0, SCREEN = 1, ERR = 2
constant TRUE = 1, FALSE = 0
constant EOF = -1
type boolean(integer x)
return x = 0 or x = 1
end type
sequence pos, cmd, string, orig_string, file_spec
boolean match_case, scan_subdirs, wild_string
integer line_count
integer scanned, skipped, no_open, total_found
scanned = 0
skipped = 0
no_open = 0
total_found = 0
atom start_time
integer log_file
function alphabetic(object s)
-- does s contain alphabetic characters?
return find(TRUE, (s >= 'A' and s <= 'Z') or
(s >= 'a' and s <= 'z'))
end function
constant LINE_WIDTH = 79
function clean(sequence line)
-- replace any funny control characters
-- and put in \n's to help break up long lines
sequence new_line
integer c, col
new_line = ""
col = 1
for i = 1 to length(line) do
if col > LINE_WIDTH then
new_line = append(new_line, '\n')
col = 1
end if
c = line[i]
col = col + 1
if c < 14 then
if c = '\t' or c = '\r' then
c = ' '
elsif c = '\n' then
col = 1
else
c = '.'
end if
end if
new_line = append(new_line, c)
end for
if length(line) > 1.5 * LINE_WIDTH then
new_line = new_line & '\n'
end if
return new_line
end function
procedure both_puts(object text)
puts(SCREEN, text)
puts(log_file, text)
end procedure
procedure both_printf(sequence format, object values)
printf(SCREEN, format, values)
printf(log_file, format, values)
end procedure
function plural(integer n)
-- Yes, this is a bit obsessive...
if n = 1 then
return ""
else
return "s"
end if
end function
procedure list_file_spec()
for i = 1 to length(file_spec) do
both_puts(file_spec[i])
if i != length(file_spec) then
both_puts(" ")
end if
end for
end procedure
procedure final_stats()
-- show final statistics
puts(SCREEN, repeat(' ', 80))
if length(string) = 0 then
both_printf("%d file name" & plural(total_found) & " matched (",
total_found)
list_file_spec()
both_puts(")\n")
both_printf("%d names did not match\n", skipped)
else
both_printf("\n%5d file" & plural(scanned) & " scanned (", scanned)
list_file_spec()
both_printf(")\n%5d file" & plural(skipped) & " skipped\n", skipped)
both_printf("%5d file" & plural(total_found) &
" contained \"%s\" ", {total_found, orig_string})
if alphabetic(orig_string) then
if match_case then
both_puts("(case must match)")
else
both_puts("(any case)")
end if
end if
both_puts('\n')
if no_open then
both_printf("couldn't open %d file" & plural(no_open) & '\n',
no_open)
end if
end if
printf(SCREEN, "search time: %.1f seconds\n", time()-start_time)
if total_found then
puts(SCREEN, "\nSee " & log_path & '\n')
end if
close(log_file)
end procedure
constant MAX_LINE = 500
-- space for largest line
sequence buff
buff = repeat(0, MAX_LINE)
function safe_gets(integer fn)
-- Return the next line of text.
-- Lines are split at MAX_LINE to prevent
-- "out of memory" problems on humongous lines
-- and to reduce the amount of extraneous output.
integer c
for b = 1 to MAX_LINE-1 do
c = getc(fn)
if c <= '\n' then
if c = '\n' then
buff[b] = c
return buff[1..b]
elsif c = EOF then
if b = 1 then
return EOF
else
exit
end if
end if
end if
buff[b] = c
end for
buff[MAX_LINE] = '\n'
return buff[1..MAX_LINE]
end function
constant SAFE_FILE_SIZE = 100000
function scan(sequence file_name, integer file_size, sequence string)
-- print all lines in current file containing the string
object line
sequence match_line
integer fileNum
boolean found, found_in_file
wrap(FALSE)
puts(SCREEN, file_name & ':' & repeat(' ', 80) & '\r')
wrap(TRUE)
fileNum = open(file_name, "rb")
if fileNum = -1 then
no_open = no_open + 1
both_puts(file_name & ": Couldn't open. Probably locked.\t\t\t\n")
return 0
end if
found_in_file = FALSE
while TRUE do
if file_size > SAFE_FILE_SIZE then
line = safe_gets(fileNum)
else
line = gets(fileNum)
end if
if atom(line) then
exit -- end of file
else
if match_case then
match_line = line
else
match_line = lower(line)
end if
if wild_string then
found = wildcard_match(string, match_line)
else
found = match(string, match_line)
end if
if found then
both_puts(clean(file_name & ": " & line))
found_in_file = TRUE
end if
end if
end while
scanned = scanned + 1
close(fileNum)
return found_in_file
end function
procedure look_at(sequence path_name, sequence entry)
-- see if a file name qualifies for searching
boolean matched_one
sequence file_name
file_name = entry[D_NAME]
if compare(file_name, log_name) = 0 then
return -- avoid circularity
end if
if compare(file_spec[1], "*.*") = 0 then
-- check skip list
for i = 1 to length(skip_list) do
if wildcard_file(skip_list[i], file_name) then
skipped = skipped + 1
return
end if
end for
else
-- go through list of file specs
matched_one = FALSE
for i = 1 to length(file_spec) do
if wildcard_file(file_spec[i], file_name) then
matched_one = TRUE
exit
end if
end for
if not matched_one then
skipped = skipped + 1
return
end if
end if
path_name = path_name & '\\'
if compare(path_name[1..2], ".\\") = 0 then
path_name = path_name[3..length(path_name)]
end if
path_name = path_name & file_name
if length(string) = 0 then
-- just looking for file names
both_printf("%4d-%02d-%02d %2d:%02d", entry[D_YEAR..D_MINUTE])
both_printf(" %7d %s\n", {entry[D_SIZE], path_name})
total_found = total_found + 1
else
total_found = total_found + scan(path_name, entry[D_SIZE], string)
end if
end procedure
procedure walk_dir(sequence path_name)
-- walk through a directory and its subdirectories
-- in alphabetical order, "looking" at each file
object d
d = dir(path_name)
while find(path_name[length(path_name)], " \\") do
path_name = path_name[1..length(path_name)-1]
end while
if atom(d) then
puts(ERR, "\nCouldn't access " & path_name & '\n')
return
end if
d = sort(d) -- sort-by-name (first field of d)
for i = 1 to length(d) do
if find('d', d[i][D_ATTRIBUTES]) then
if not find(d[i][D_NAME], {".", ".."}) then
if scan_subdirs then
walk_dir(path_name & '\\' & d[i][D_NAME])
end if
end if
else
look_at(path_name, d[i])
end if
if get_key() = 'q' then
final_stats()
abort(1)
end if
end for
end procedure
function blank_delim(sequence s)
-- break up a blank-delimited string
sequence list, segment
integer i
list = {}
i = 1
while i < length(s) do
while find(s[i], " \t") do
i = i + 1
end while
if s[i] = '\n' then
exit
end if
segment = ""
while not find(s[i], " \t\n") do
segment = segment & s[i]
i = i + 1
end while
list = append(list, segment)
end while
return list
end function
procedure get_file_spec()
-- read in a list of file specifications from user
-- result is stored in file_spec sequence of strings
sequence spec
puts(SCREEN, "file-spec (*.*): ")
spec = gets(KEYB)
puts(SCREEN, '\n')
file_spec = blank_delim(spec)
if length(file_spec) = 0 then
file_spec = {"*.*"}
end if
end procedure
log_name = upper(log_name)
cmd = command_line() -- ex search.ex [string]
if length(cmd) >= 3 then
orig_string = cmd[3]
else
puts(SCREEN, "string:")
orig_string = gets(KEYB)
orig_string = orig_string[1..length(orig_string)-1] -- remove \n
puts(SCREEN, '\n')
end if
if alphabetic(orig_string) then
puts(SCREEN, "match case? (n)")
pos = get_position()
position(pos[1], pos[2] - 2)
match_case = find('y', gets(KEYB))
puts(SCREEN, '\n')
else
match_case = TRUE
end if
string = orig_string
if not match_case then
string = lower(string)
end if
wild_string = find('?', string) or find('*', string)
if wild_string then
string = '*' & string & '*' -- to match whole line
end if
get_file_spec()
-- avoid asking about subdirectories
-- when there aren't any...
object d
d = dir(current_dir())
if atom(d) then
puts(SCREEN, "network drive not available\n")
abort(1)
end if
for i = 1 to length(d) do
if find('d', d[i][D_ATTRIBUTES]) then
if not find(d[i][D_NAME], {".", ".."}) then
puts(SCREEN, "scan subdirectories? (y)")
pos = get_position()
position(pos[1], pos[2] - 2)
scan_subdirs = not match("n", gets(KEYB))
exit
end if
end if
end for
puts(SCREEN, "\npress q to quit\n\n")
log_file = open(log_path, "w")
if log_file = -1 then
puts(ERR, "Couldn't open " & log_path & '\n')
abort(1)
end if
start_time = time()
if sequence(dir(".")) then
puts(log_file, "Searching " & current_dir() & "\n\n")
walk_dir(".")
else
walk_dir(current_dir())
end if
final_stats()
without warning